//this file is part of eMule
//Copyright (C)2002 Merkur ( merkur-@users.sourceforge.net / http://www.emule-project.net )
//
//This program is free software; you can redistribute it and/or
//modify it under the terms of the GNU General Public License
//as published by the Free Software Foundation; either
//version 2 of the License, or (at your option) any later version.
//
//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//GNU General Public License for more details.
//
//You should have received a copy of the GNU General Public License
//along with this program; if not, write to the Free Software
//Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

#include "wintypes.h"
#include "emule.h"
#include "ListenSocket.h"
#include "opcodes.h"
#include "KnownFile.h"
#include "SharedFileList.h"
#include "UploadQueue.h"
#include "updownclient.h"
#include "ClientList.h"
#include "Friend.h"

extern char* nstrdup(char*);

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

// prevent fscking dns queries
class emuleIPV4Address : public wxIPV4address {
public:
  emuleIPV4Address() : wxIPV4address() {};
  virtual bool Hostname(unsigned long addr) {
    return GAddress_INET_SetHostAddress(m_address,addr)==GSOCK_NOERROR;
  };
  virtual bool Hostname(char* addr) {
    struct in_addr inaddr;
    inet_aton(addr,&inaddr);
    return GAddress_INET_SetHostAddress(m_address,inaddr.s_addr)==GSOCK_NOERROR;
  }
};


//	members of CUpDownClient
//	which are used by down and uploading functions 

CUpDownClient::CUpDownClient(CClientReqSocket* sender){
	socket = sender;
	reqfile = 0;
	Init();
}

CUpDownClient::CUpDownClient(uint16 in_port, uint32 in_userid,uint32 in_serverip, uint16 in_serverport,CPartFile* in_reqfile){
	socket = 0;
	Init();
	m_nUserID = in_userid;
	m_nUserPort = in_port;
	sourcesslot=m_nUserID%SOURCESSLOTS;
	if (!HasLowID())
		sprintf(m_szFullUserIP,"%i.%i.%i.%i",(uint8)m_nUserID,(uint8)(m_nUserID>>8),(uint8)(m_nUserID>>16),(uint8)(m_nUserID>>24));
	m_dwServerIP = in_serverip;
	m_nServerPort = in_serverport;
	reqfile = in_reqfile;
	ReGetClientSoft();
}

void CUpDownClient::Init(){
	memset(m_szFullUserIP,0,21);
	credits = 0;
	m_nAvDownDatarate = 0;
	m_nAvUpDatarate = 0;
	m_byChatstate = 0;
	m_cShowDR = 0;
	m_nUDPPort = 0;
	m_cFailed = 0;
	m_dwBanTime = 0;
	m_nMaxSendAllowed = 0;
	m_nTransferedUp = 0;
	m_cSendblock = 0;
	m_cAsked = 0;
	m_cDownAsked = 0;
	dataratems = 0;
	m_nUpDatarate = 0;
	m_pszUsername = 0;
	m_dwUserIP = 0;
	m_nUserID = 0;
	m_nServerPort = 0;
	m_bBanned = false;
	m_bFileListRequested = false;
	m_dwLastUpRequest = 0;
	m_bEmuleProtocol = false;
	usedcompressiondown = false;
	m_bUsedComprUp = false;
	m_bCompleteSource = false;
	m_bFriendSlot = false;
	m_bCommentDirty = false;
	m_bReaskPending = false;
	m_bUDPPending = false;
	m_byEmuleVersion = 0;
	m_nUserPort = 0;
	m_nPartCount = 0;
	m_nUpPartCount = 0;
	m_abyPartStatus = 0;
	m_abyUpPartStatus = 0;
	m_dwLastAskedTime = 0;
	m_nDownloadState = DS_NONE;
	m_pszClientFilename = 0;
	m_dwUploadTime = 0;
	m_nTransferedDown = 0;
	m_nDownDatarate = 0;
	m_nDownDataRateMS = 0;
	m_byUploadState = US_NONE;
	m_dwLastBlockReceived = 0;
	m_byEmuleVersion = 0;
	m_byDataCompVer = 0;
	m_byUDPVer = 0;
	m_bySourceExchangeVer = 0;
	m_byAcceptCommentVer = 0;
	m_byExtendedRequestsVer = 0;
	m_nRemoteQueueRank = 0;
	m_dwLastSourceRequest = 0;
	m_dwLastSourceAnswer = 0;
	m_byCompatableClient = 0;
	m_bIsHybrid = false;
	m_bIsNewMLD = false;
	m_Friend = NULL;
	m_iRate=0;
	m_strComment="";
	m_nCurSessionUp = 0;
	m_nSumForAvgDownDataRate = 0;
	m_nSumForAvgUpDataRate = 0;
	m_clientSoft=SO_UNKNOWN;
	m_bRemoteQueueFull = false;
	memset( m_achUserHash, 0, 16);
	SetWaitStartTime();
	if (socket){
		struct sockaddr_in sockAddr;
		memset(&sockAddr, 0, sizeof(sockAddr));
		uint32 nSockAddrLen = sizeof(sockAddr);
		wxIPV4address address;
		socket->GetPeer(address);
		//socket->GetPeerName((SOCKADDR*)&sockAddr,(int*)&nSockAddrLen);
		sockAddr.sin_addr.s_addr=GAddress_INET_GetHostAddress(address.GetAddress());
		m_dwUserIP = sockAddr.sin_addr.s_addr;
		strcpy(m_szFullUserIP,inet_ntoa(sockAddr.sin_addr));
	}
	sourcesslot=0;
}

CUpDownClient::~CUpDownClient(){
	//Beep(400,5);

	theApp.clientlist->RemoveClient(this);
	if (m_Friend){
		m_Friend->m_LinkedClient = NULL;
		theApp.friendlist->RefreshFriend(m_Friend);
		m_Friend = NULL;
	}
	if (m_pszClientFilename)
		delete[] m_pszClientFilename;
	if (socket){
		socket->client = 0;
		socket->Safe_Delete();
	}
	if (m_pszUsername)
		delete[] m_pszUsername;
	if (m_abyPartStatus)
		delete[] m_abyPartStatus;
	if (m_abyUpPartStatus)
		delete[] m_abyUpPartStatus;
	
	ClearUploadBlockRequests();

	for (POSITION pos = m_DownloadBlocks_list.GetHeadPosition();pos != 0;m_DownloadBlocks_list.GetNext(pos))
		delete m_DownloadBlocks_list.GetAt(pos);
	m_DownloadBlocks_list.RemoveAll();
	for (POSITION pos = m_RequestedFiles_list.GetHeadPosition();pos != 0;m_RequestedFiles_list.GetNext(pos))
		delete m_RequestedFiles_list.GetAt(pos);
	m_RequestedFiles_list.RemoveAll();
	for (POSITION pos = m_PendingBlocks_list.GetHeadPosition();pos != 0;m_PendingBlocks_list.GetNext(pos)){
		Pending_Block_Struct *pending = m_PendingBlocks_list.GetAt(pos);
		delete pending->block;
		// Not always allocated
		if (pending->zStream) {
		  inflateEnd(pending->zStream);
		  delete pending->zStream;
		}
		delete pending;
	}

	if (m_iRate>0 || m_strComment.GetLength()>0) {
		m_iRate=0; m_strComment="";
		reqfile->UpdateFileRatingCommentAvail();
	}


	m_PendingBlocks_list.RemoveAll();
	m_AvarageUDR_list.RemoveAll();
	m_AvarageDDR_list.RemoveAll();
	//DEBUG_ONLY (theApp.listensocket->Debug_ClientDeleted(this));
}

void CUpDownClient::ProcessHelloPacket(char* pachPacket, uint32 nSize){
	CSafeMemFile* data = new CSafeMemFile((BYTE*)pachPacket,nSize);
	uint8 hashsize;
	data->Read(&hashsize,1);
	this->ProcessHelloTypePacket(data);
	delete data;
}

void CUpDownClient::ProcessHelloAnswer(char* pachPacket, uint32 nSize){
	CSafeMemFile* data = new CSafeMemFile((BYTE*)pachPacket,nSize);
	this->ProcessHelloTypePacket(data);
	delete data;
}

void CUpDownClient::ProcessHelloTypePacket(CSafeMemFile* data){
	data->Read(&m_achUserHash,16);
	uint32 nUserID;
	data->Read(&nUserID,4);
	if (!m_nUserID || nUserID < 16777216)
		m_nUserID = nUserID;
	data->Read(&m_nUserPort,2); // hmm clientport is sent twice - why?
	uint32	tagcount;
	data->Read(&tagcount,4);

/* 
It seems that sometimes tagcount can return negative value, causing endless loop 
here. This check should avoid it. 
*/

	if ((tagcount>0) && (tagcount<1000)) {
		for (int i = 0;i != tagcount; i++){
			CTag* temptag = new CTag(data);
			switch(temptag->tag->specialtag){
				case CT_NAME:
					if (m_pszUsername)
						delete[] m_pszUsername;
					m_pszUsername = nstrdup(temptag->tag->stringvalue);
					break;
				case CT_VERSION:
					m_nClientVersion = temptag->tag->intvalue;
					break;
				case CT_PORT:
					m_nUserPort = temptag->tag->intvalue;
					break;
			}
			delete temptag;
		}
	}
	data->Read(&m_dwServerIP,4);
	data->Read(&m_nServerPort,2);
	// Hybrid now has an extra uint32.. What is it for?
	// Also, many clients seem to send an extra 6? These are not eDonkeys or Hybrids..
	if ( data->GetLength() - data->GetPosition() == 4 ){
		uint32 test;
		data->Read(&test,4);
		if (test==1262767181) 
		   m_bIsNewMLD = true;
	        else
		   m_bIsHybrid = true;
//		if( m_nClientVersion > 10000 && m_nClientVersion < 100000 )
//			m_nClientVersion = m_nClientVersion - (m_nClientVersion/10000)*10000;
//		if( m_nClientVersion > 1000 )
//			m_nClientVersion = m_nClientVersion - (m_nClientVersion/1000)*1000;
//		if( m_nClientVersion < 100 )
//			m_nClientVersion *= 10;
	}
	// tecxx 1609 2002 - add client's servet to serverlist (Moved to uploadqueue.cpp)

	struct sockaddr_in sockAddr;
	memset(&sockAddr, 0, sizeof(sockAddr));
	uint32 nSockAddrLen = sizeof(sockAddr);
	wxIPV4address address;
	socket->GetPeer(address);
	sockAddr.sin_addr.s_addr=GAddress_INET_GetHostAddress(address.GetAddress());
	//socket->GetPeerName((SOCKADDR*)&sockAddr,(int*)&nSockAddrLen);
	m_dwUserIP = sockAddr.sin_addr.s_addr;
	strcpy(m_szFullUserIP,inet_ntoa(sockAddr.sin_addr));

	if (theApp.glob_prefs->AddServersFromClient()){
		in_addr addhost;
		addhost.s_addr = m_dwServerIP;
		CServer* addsrv = new CServer(m_nServerPort, inet_ntoa(addhost));
		addsrv->SetListName(addsrv->GetAddress());

		if (!theApp.emuledlg->serverwnd->serverlistctrl->AddServer(addsrv, true))
			delete addsrv;
		/*else
			theApp.emuledlg->AddLogLine(false,"Added new server: %s:%d", srv->GetFullIP(), srv->GetPort());*/
	}

	// get client credits
	// key, 255.255.0.0 subnetmask
	if(!HasLowID() && m_nUserID != m_dwUserIP)
		m_nUserID = m_dwUserIP;

	uchar key[16];
	memcpy(key,m_achUserHash,16);
	credits = theApp.clientcredits->GetCredit(key);
	if ( (m_Friend = theApp.friendlist->LinkFriend(key, m_dwUserIP, m_nUserPort) ) != NULL){
		m_Friend->m_LinkedClient = this;
		m_Friend->m_dwHasHash = 1;
		for( int i = 0; i < 16; i++ )
			m_Friend->m_abyUserhash[i] = GetUserHash()[i];
		m_Friend->m_strName.Format("%s", m_pszUsername);
		m_Friend->m_dwLastUsedIP = m_dwUserIP;
		m_Friend->m_nLastUsedPort = m_nUserPort;
		theApp.friendlist->RefreshFriend(m_Friend);
	}
	ReGetClientSoft();
}

void CUpDownClient::SendHelloPacket(){
	if (socket){
	  struct sockaddr_in sockAddr;
		memset(&sockAddr, 0, sizeof(sockAddr));
		uint32 nSockAddrLen = sizeof(sockAddr);
		//socket->GetPeerName((SOCKADDR*)&sockAddr,(int*)&nSockAddrLen);
		wxIPV4address address;
		socket->GetPeer(address);
		sockAddr.sin_addr.s_addr=GAddress_INET_GetHostAddress(address.GetAddress());
		if ( theApp.ipfilter->IsFiltered(sockAddr.sin_addr.s_addr)) {
			theApp.emuledlg->AddDebugLogLine(true,GetResString(IDS_IPFILTERED).GetData(),GetFullIP(),theApp.ipfilter->GetLastHit().GetData());
			Disconnected();
			theApp.stat_filteredclients++;
			return;
		}
	}
	CMemFile* data = new CMemFile();
	uint8 hashsize = 16;
	data->Write(&hashsize,1);
	SendHelloTypePacket(data);
	Packet* packet = new Packet(data);
	delete data;
	packet->opcode = OP_HELLO;
	if (socket) {
		theApp.uploadqueue->AddUpDataOverheadOther(packet->size);
		socket->SendPacket(packet,true);
	}
}

void CUpDownClient::SendMuleInfoPacket(bool bAnswer){
	CMemFile* data = new CMemFile();
	uint8 version = CURRENT_VERSION_SHORT;
	data->Write(&version,1);
	uint8 protversion = EMULE_PROTOCOL;
	data->Write(&protversion,1);
	uint32 tagcount = 7;
	data->Write(&tagcount,4);
	CTag tag(ET_COMPRESSION,1);
	tag.WriteTagToFile(data);
	CTag tag2(ET_UDPVER,2);
	tag2.WriteTagToFile(data);
	CTag tag3(ET_UDPPORT,theApp.glob_prefs->GetUDPPort());
	tag3.WriteTagToFile(data);
	CTag tag4(ET_SOURCEEXCHANGE,1);
	tag4.WriteTagToFile(data);
	CTag tag5(ET_COMMENTS,1);
	tag5.WriteTagToFile(data);
	CTag tag6(ET_EXTENDEDREQUEST,1);
	tag6.WriteTagToFile(data);
	CTag tag7(ET_COMPATABLECLIENT,2);
	tag7.WriteTagToFile(data);
	Packet* packet = new Packet(data,OP_EMULEPROT);
	delete data;
	if (!bAnswer)
		packet->opcode = OP_EMULEINFO;
	else
		packet->opcode = OP_EMULEINFOANSWER;
	if (socket){
		theApp.uploadqueue->AddUpDataOverheadOther(packet->size);
		socket->SendPacket(packet,true,true);
	}
}

void CUpDownClient::ProcessMuleInfoPacket(char* pachPacket, uint32 nSize){
	CSafeMemFile* data = new CSafeMemFile((BYTE*)pachPacket,nSize);
	m_byCompatableClient = 0;
	data->Read(&m_byEmuleVersion,1);
	if( m_byEmuleVersion == 0x2B )
		m_byEmuleVersion = 0x22;
	uint8 protversion;
	data->Read(&protversion,1);

	//implicitly supported options by older clients
	if (protversion == EMULE_PROTOCOL) {
		//in the future do not use version to guess about new features

		if(m_byEmuleVersion < 0x25 && m_byEmuleVersion > 0x22)
			m_byUDPVer = 1;

		if(m_byEmuleVersion < 0x25 && m_byEmuleVersion > 0x21)
			m_bySourceExchangeVer = 1;

		if(m_byEmuleVersion == 0x24)
			m_byAcceptCommentVer = 1;

	} else {
		delete data;
		return;
	}
	m_bEmuleProtocol = true;

	uint32 tagcount;
	data->Read(&tagcount,4);
	for (int i = 0;i != tagcount; i++){
		CTag* temptag = new CTag(data);
		switch(temptag->tag->specialtag){
			case ET_COMPRESSION:
				m_byDataCompVer = temptag->tag->intvalue;
				break;
			case ET_UDPPORT:
				m_nUDPPort = temptag->tag->intvalue;
				break;
			case ET_UDPVER:
				m_byUDPVer = temptag->tag->intvalue;
				break;
			case ET_SOURCEEXCHANGE:
				m_bySourceExchangeVer = temptag->tag->intvalue;
				break;
			case ET_COMMENTS:
				m_byAcceptCommentVer = temptag->tag->intvalue;
				break;
			case ET_EXTENDEDREQUEST:
				m_byExtendedRequestsVer = temptag->tag->intvalue;
				break;
			case ET_COMPATABLECLIENT:
				m_byCompatableClient = temptag->tag->intvalue;
				break;
		}
		delete temptag;
	}
	if( m_byDataCompVer == 0 ){
		m_bySourceExchangeVer = 0;
		m_byExtendedRequestsVer = 0;
		m_byAcceptCommentVer = 0;
		m_nUDPPort = 0;
	}
	delete data;
}

void CUpDownClient::SendHelloAnswer(){
	CMemFile* data = new CMemFile();
	SendHelloTypePacket(data);
	Packet* packet = new Packet(data);
	delete data;
	packet->opcode = OP_HELLOANSWER;
	if (socket){
		theApp.uploadqueue->AddUpDataOverheadOther(packet->size);
		socket->SendPacket(packet,true);
	}
}

void CUpDownClient::SendHelloTypePacket(CMemFile* data){
	data->Write(theApp.glob_prefs->GetUserHash(),16);
	uint32 clientid = theApp.serverconnect->GetClientID();
	data->Write(&clientid,4);
	uint16 nPort = theApp.glob_prefs->GetPort();
	data->Write(&nPort,2);
	uint32 tagcount = 2;
	data->Write(&tagcount,4);
	CTag* tag = new CTag(CT_NAME,theApp.glob_prefs->GetUserNick());
	tag->WriteTagToFile(data);
	delete tag;
	tag = new CTag(CT_VERSION,EDONKEYVERSION);
	tag->WriteTagToFile(data);
	delete tag;
//	tag = new CTag(CT_PORT,theApp.glob_prefs->GetPort());
//	tag->WriteTagToFile(data);
//	delete tag;
	uint32 dwIP;
	if (theApp.serverconnect->IsConnected()){
		dwIP = theApp.serverconnect->GetCurrentServer()->GetIP();
		nPort = theApp.serverconnect->GetCurrentServer()->GetPort();
	}
	else{
		nPort = 0;
		dwIP = 0;
	}
	data->Write(&dwIP,4);
	data->Write(&nPort,2);
}


void CUpDownClient::ProcessMuleCommentPacket(char* pachPacket, uint32 nSize){
	if (nSize>2){
		CSafeMemFile data((BYTE*)pachPacket,nSize);
		int length;
		data.Read(&m_iRate,sizeof(m_iRate));
		data.Read(&length,sizeof(length));
		reqfile->SetHasRating(true);
		theApp.emuledlg->AddDebugLogLine(false,GetResString(IDS_RATINGRECV),m_pszClientFilename,m_iRate);
		if (length>50) length=50;
		if (length>0){
			char* desc=new char[length+1];
			memset(desc,0,length+1);
			data.Read(desc,length);
			theApp.emuledlg->AddDebugLogLine(false,GetResString(IDS_DESCRIPTIONRECV), m_pszClientFilename, desc);
			m_strComment.Format("%s",desc);
			reqfile->SetHasComment(true);
			delete desc;
		}

	}
	if (reqfile->HasRating() || reqfile->HasComment()) theApp.emuledlg->transferwnd->downloadlistctrl->UpdateItem(reqfile);
}
void CUpDownClient::Disconnected(){
  //assert(theApp.clientlist->Debug_IsValidClient(this));
	if (GetUploadState() == US_UPLOADING)
		theApp.uploadqueue->RemoveFromUploadQueue(this);
	if (GetDownloadState() == DS_DOWNLOADING){
		SetDownloadState(DS_ONQUEUE);
	}
	if ((GetDownloadState() == DS_REQHASHSET) && (reqfile))
        reqfile->hashsetneeded= true;
	//assert(theApp.clientlist->Debug_IsValidClient(this));
	//check if this client is needed in any way, if not delete it
	bool bDelete = true;
	switch(m_byUploadState){
		case US_ONUPLOADQUEUE:
			bDelete = false;
	};
	switch(m_nDownloadState){
		case DS_ONQUEUE:
		case DS_TOOMANYCONNS:
		case DS_NONEEDEDPARTS:
		case DS_LOWTOLOWIP:
			bDelete = false;
	};

	switch(m_byUploadState){
		case US_CONNECTING:
		case US_WAITCALLBACK:
		case US_ERROR:
			bDelete = true;
	};
	switch(m_nDownloadState){
		case DS_CONNECTING:
		{
			m_cFailed++;
			if (m_cFailed <= 2){
				TryToConnect();
				return;
			}
		}
		case DS_WAITCALLBACK:{
		case DS_ERROR:
			bDelete = true;
		}
	};
	

	if (GetChatState()){
		bDelete = false;
		//theApp.emuledlg->chatwnd.chatselector.ConnectingResult(this,false);
#warning CHATSELECTOR MISSING
	}
	if (socket){
	  //ASSERT (theApp.listensocket->IsValidSocket(socket));
	  socket->Safe_Delete();
	  //delete socket;
	}
	socket = 0;
	if (m_bFileListRequested){
		theApp.emuledlg->AddDebugLogLine(false,GetResString(IDS_SHAREDFILES_FAILED),GetUserName());
		m_bFileListRequested = false;
	}
	if (m_Friend)
	  theApp.friendlist->RefreshFriend(m_Friend);
	if (bDelete){
		delete this;
	}

}

void CUpDownClient::TryToConnect(bool bIgnoreMaxCon){
	if (theApp.listensocket->TooManySockets() && !bIgnoreMaxCon && !(socket && socket->IsConnected())){
		Disconnected();
		return;
	}
	if ((theApp.serverconnect->GetClientID() < 16777216) && HasLowID()){
		if (GetDownloadState() == DS_CONNECTING)
			SetDownloadState(DS_LOWTOLOWIP);
		else if (GetDownloadState() == DS_REQHASHSET){
			SetDownloadState(DS_ONQUEUE);
			reqfile->hashsetneeded = true;
		}
		if (GetUploadState() == US_CONNECTING){
			Disconnected();
		}
	}

	if (!socket){
		socket = new CClientReqSocket(theApp.glob_prefs,this);
		if (!socket->Create()){
			socket->Safe_Delete();
			return;
		}
	}
	else if (!socket->IsConnected()){
		socket->Safe_Delete();
		socket = new CClientReqSocket(theApp.glob_prefs,this);
		if (!socket->Create()){
			socket->Safe_Delete();
			return;
		}
	}
	else{
		ConnectionEstablished();
		return;
	}
	if (HasLowID()){
		if (GetDownloadState() == DS_CONNECTING)
			SetDownloadState(DS_WAITCALLBACK);
		if (GetUploadState() == US_CONNECTING){
			Disconnected();
			return;
		}

		if (theApp.serverconnect->IsLocalServer(m_dwServerIP,m_nServerPort)){
			Packet* packet = new Packet(OP_CALLBACKREQUEST,4);
			memcpy(packet->pBuffer,&m_nUserID,4);
			theApp.uploadqueue->AddUpDataOverheadServer(packet->size);
			theApp.serverconnect->SendPacket(packet);
		}
		else{
			if (GetUploadState() == US_NONE && (!GetRemoteQueueRank() || m_bReaskPending) ){
				theApp.downloadqueue->RemoveSource(this);
				Disconnected();
				return;
			}
			else{
				if (GetDownloadState() == DS_WAITCALLBACK){
					m_bReaskPending = true;
					SetDownloadState(DS_ONQUEUE);
				}
			}
		}
	}
	// MOD Note - end
	else{
	  emuleIPV4Address tmp;
	  tmp.Hostname(GetFullIP());
	  tmp.Service(GetUserPort());
	  socket->Connect(tmp,FALSE);
	  //socket->Connect(GetFullIP(),GetUserPort());
	  SendHelloPacket();
	}
}

void CUpDownClient::ConnectionEstablished(){
	m_cFailed = 0;
	// ok we have a connection, lets see if we want anything from this client
	if (GetChatState() == MS_CONNECTING) {
	  //theApp.emuledlg->chatwnd.chatselector.ConnectingResult(this,true);
#warning CHATSELECTOR MISSING
	}

	switch(GetDownloadState()){
		case DS_CONNECTING:
		case DS_WAITCALLBACK:
			m_bReaskPending = false;
			SetDownloadState(DS_CONNECTED);
			SendFileRequest();
	}
	if (m_bReaskPending){
		m_bReaskPending = false;
		if (GetDownloadState() != DS_NONE && GetDownloadState() != DS_DOWNLOADING){
			SetDownloadState(DS_CONNECTED);
			SendFileRequest();
		}
	}
	switch(GetUploadState()){
		case US_CONNECTING:
		case US_WAITCALLBACK:
			if (theApp.uploadqueue->IsDownloading(this)){
				SetUploadState(US_UPLOADING);
				Packet* packet = new Packet(OP_ACCEPTUPLOADREQ,0);
				theApp.uploadqueue->AddUpDataOverheadFileRequest(packet->size);
				socket->SendPacket(packet,true);
			}
	}
	if (m_bFileListRequested){
		Packet* packet = new Packet(OP_ASKSHAREDFILES,0);
		theApp.uploadqueue->AddUpDataOverheadOther(packet->size);
		socket->SendPacket(packet,true,true);
	}
}

void CUpDownClient::ReGetClientSoft(){
	if (!m_pszUsername) {m_clientSoft=SO_UNKNOWN;return;}
	if( m_bIsHybrid ) {m_clientSoft=SO_EDONKEYHYBRID;return;}
	if( m_bIsNewMLD ) {m_clientSoft=SO_NEW_MLDONKEY;return;}
	if (m_achUserHash[5] == 13 && m_achUserHash[14] == 110) {m_clientSoft= SO_OLDEMULE;return;}
	if (m_achUserHash[5] == 14 && m_achUserHash[14] == 111){
		if( m_byCompatableClient == 1 ){
			m_clientSoft= SO_CDONKEY;
			return;
		}
		else if( m_byCompatableClient == 2 ){
			m_clientSoft= SO_LMULE;
			return;
		}
		else{
			m_clientSoft= SO_EMULE;
			return;
		}
	}
	if (m_achUserHash[5] == 'M' && m_achUserHash[14] == 'L') {m_clientSoft= SO_MLDONKEY;return;}
	else
		m_clientSoft=SO_EDONKEY;
}


void CUpDownClient::SetUserName(char* pszNewName){
	if (m_pszUsername)
		delete[] m_pszUsername;
	if( pszNewName )
		m_pszUsername = nstrdup(pszNewName);
	else
		m_pszUsername = NULL;
}

void CUpDownClient::RequestSharedFileList(){
	theApp.emuledlg->AddDebugLogLine(true,GetResString(IDS_SHAREDFILES_REQUEST),GetUserName());
	m_bFileListRequested = true;
	TryToConnect(true);
}

void CUpDownClient::ProcessSharedFileList(char* pachPacket, uint32 nSize){
	if (m_bFileListRequested){
		m_bFileListRequested = false;
		theApp.searchlist->ProcessSearchanswer(pachPacket,nSize,this);
	}
}

wxString CUpDownClient::GetUploadFileInfo()
{
  if(this == NULL) return "";
  wxString sRet;
 
  // build info text and display it
  sRet.Printf(GetResString(IDS_USERINFO), GetUserName(), GetUserID());
  if (reqfile)
    {
      sRet += GetResString(IDS_SF_REQUESTED) + wxString(reqfile->GetFileName()) + "\n";
      wxString stat;
      stat.Printf(GetResString(IDS_FILESTATS_SESSION)+GetResString(IDS_FILESTATS_TOTAL),
		  reqfile->statistic.GetAccepts(), reqfile->statistic.GetRequests(), CastItoXBytes(reqfile->statistic.GetTransfered()).GetData(),
		  reqfile->statistic.GetAllTimeAccepts(),
		  reqfile->statistic.GetAllTimeRequests(), CastItoXBytes(reqfile->statistic.GetAllTimeTransfered()).GetData() );
      sRet += stat;
    }
  else
    {
      sRet += GetResString(IDS_REQ_UNKNOWNFILE);
    }
  return sRet;
  
  return "";
}

void CUpDownClient::Destroy()
{
	socket->Destroy();

}
